#include "../../config.h"

#include <glibmm/i18n.h>

#include "../application.h"
#include "p_dialog.h"
#include "p_network.h"
#include "p_macros.h"

namespace gpyp {
namespace pref {

//========================
// YPList
void YPList::enable_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererToggle *>(cell)
    ->set_active(*get_item(iter)->enable());
}
void YPList::icon_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<CellRendererIcon *>(cell)
    ->set_icon_name(*get_item(iter)->icon());
}
void YPList::name_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererText *>(cell)
    ->property_text() = *get_item(iter)->name();
}
void YPList::url_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererText *>(cell)
    ->property_text() = *get_item(iter)->url();
}
void YPList::encoding_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererText *>(cell)
    ->property_text() = *get_item(iter)->encoding();
}
void YPList::type_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<CellRendererYPType *>(cell)
    ->set_value(*get_item(iter)->type());
}
void YPList::pcraw_proxy_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererToggle *>(cell)
    ->set_active(*get_item(iter)->pcraw_proxy());
}
void YPList::reload_interval_on_cell_data(Gtk::CellRenderer *cell, const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererText *>(cell)
    ->property_text() = tostr(*get_item(iter)->reload_interval());
}

void YPList::enable_on_toggled(const Glib::ustring &path) {
  RefYellowPage yp = get_item(path);
  yp->enable() = !*yp->enable();
}
void YPList::icon_on_edited(const Glib::ustring &path, const Glib::ustring &new_icon_name) {
  get_item(path)->icon() = new_icon_name;
}
void YPList::name_on_edited(const Glib::ustring &path, const Glib::ustring &new_text) {
  get_item(path)->name() = new_text;
}
void YPList::url_on_edited(const Glib::ustring &path, const Glib::ustring &new_text) {
  try {
    URL url(new_text);
    const std::string &url_path = url.get_path();
    if (url_path.empty() ||
        url_path.at(url_path.size() - 1) != '/') {
      WarningDialog(parent_, _("If you set directory, "
                               "URL should be terminated by '/'.")).run();
    }
    get_item(path)->url() = url.to_string();
  } catch(InvalidURL &ex) {
    ErrorDialog(parent_, ex.what()).run();
  }
}
void YPList::encoding_on_edited(const Glib::ustring &path, const Glib::ustring &new_text) {
  get_item(path)->encoding() = new_text;
}
void YPList::type_on_changed(const Glib::ustring &path, YPType type) {
  get_item(path)->type() = type;
}
void YPList::pcraw_proxy_on_toggled(const Glib::ustring &path) {
  RefYellowPage yp = get_item(path);
  yp->pcraw_proxy() = !*yp->pcraw_proxy();
}
void YPList::reload_interval_on_edited(const Glib::ustring &path, const Glib::ustring &new_text) {
  get_item(path)->reload_interval() = toint(new_text, 0);
}

void YPList::add_favorite() {
  Gtk::TreeIter iter_sel = get_selection()->get_selected();
  if (!iter_sel) {
    log::err << "YP not selected" << log::endl;
    return;
  }
  RefYellowPage yp = get_item(iter_sel);
  if (!yp) {
    log::err << "failed to get selected yp" << log::endl;
    return;
  }

  RefFavoriteCollection fc = app_.favcollection();
  if (fc->find(*yp->name())) {
    ErrorDialog(parent_, format(_("Already have favorite - \"%s\""),
                                (*yp->name()).c_str())).run();
    return;
  }

  Dialog *dialog = dynamic_cast<Dialog *>(&parent_);
  if (dialog) dialog->init_page(PREF_PAGE_FAVORITE);

  RefFavorite fav = fc->add_item(*yp->name(), true, true);
  fav->add_item(Glib::ustring("^") + Regex::escape(*yp->name()) + "$",
                gpyp::Rule::TARGET_YPNAME, true);

  RefFavorite prev, next;
  Gtk::TreeNodeChildren children = liststore_->children();
  if (iter_sel == children.begin()) {
    for(Gtk::TreeIter iter = ++children.begin();
        iter != children.end(); ++iter) {
      RefFavorite fav = fc->find(*get_item(iter)->name());
      if (fav) {
        next = fav;
        break;
      }
    }
  } else {
    Gtk::TreeIter iter = iter_sel;
    for(--iter; iter != children.begin(); --iter) {
      RefFavorite fav = fc->find(*get_item(iter)->name());
      if (fav) {
        prev = fav;
        break;
      }
    }
    if (!prev) {
      iter = iter_sel;
      for(++iter; iter != children.end(); ++iter) {
        RefFavorite fav = fc->find(*get_item(iter)->name());
        if (fav) {
          next = fav;
          break;
        }
      }
    }
  }
  if (prev || next) {
    fc->reorder_item(fav, prev, next);
  } else {
    log::err << "failed to detect previous or next favorite" << log::endl;
  }

  if (dialog) dialog->show(PREF_PAGE_FAVORITE);
}

YPList::YPList(Application &app, Gtk::Window &parent) :
  ListView<YPCollection> (app.ypcollection()),
  app_                   (app),
  parent_                (parent),
  renderer_icon_         (parent),
  column_enable_         ("",            renderer_enable_),
  column_icon_           (_("Icon"),     renderer_icon_),
  column_name_           (_("Name"),     renderer_name_),
  column_url_            (_("URL"),      renderer_url_),
  column_encoding_       (_("Encoding"), renderer_encoding_),
  column_type_           (_("Type"),     renderer_type_),
  column_pcraw_proxy_    (_("PCRaw"),    renderer_pcraw_proxy_),
  column_reload_interval_(_("Reload"),   renderer_reload_interval_)
{
  renderer_name_.property_editable() = true;
  renderer_url_.property_editable() = true;
  renderer_url_.property_ellipsize() = Pango::ELLIPSIZE_END;
  renderer_encoding_.property_editable() = true;
  renderer_type_.property_editable() = true;
  renderer_reload_interval_.property_editable() = true;
#ifdef GTK_HAVE_CELL_RENDERER_SPIN
  g_object_set(renderer_reload_interval_.gobj(),
               "adjustment", gtk_adjustment_new(10, 0, 120, 1, 10, 0),
               NULL);
#endif

#define CELL_DATA(N)                                                    \
  column_##N##_.set_cell_data_func(renderer_##N##_, sigc::mem_fun(*this, &YPList::N##_on_cell_data))
  CELL_DATA(enable);
  CELL_DATA(icon);
  CELL_DATA(name);
  CELL_DATA(url);
  CELL_DATA(encoding);
  CELL_DATA(type);
  CELL_DATA(pcraw_proxy);
  CELL_DATA(reload_interval);
#undef CELL_DATA

#define CONN_EDITED(N, S)                                       \
  renderer_##N##_.signal_##S()                                  \
    .connect(sigc::mem_fun(*this, &YPList::N##_on_##S))
  CONN_EDITED(enable,          toggled);
  CONN_EDITED(icon,            edited);
  CONN_EDITED(name,            edited);
  CONN_EDITED(url,             edited);
  CONN_EDITED(encoding,        edited);
  CONN_EDITED(type,            changed);
  CONN_EDITED(pcraw_proxy,     toggled);
  CONN_EDITED(reload_interval, edited);
#undef CONN_EDITED

  column_url_.set_expand(true);

  append_column(column_enable_);
  append_column(column_icon_);
  append_column(column_name_);
  append_column(column_url_);
  append_column(column_encoding_);
  append_column(column_type_);
  append_column(column_pcraw_proxy_);
  append_column(column_reload_interval_);
}

//========================
// Network
void Network::ua_on_changed() {
#ifdef GTK_HAVE_TOOLTIP
  useragent_.set_tooltip_text(app_.conf().network()->useragent()->get_ua());
#endif
}

Network::Network(Application &app, Gtk::Window &parent) :
  Gtk::VBox          (false, 2),
  app_               (app),
  peercast_server_   (app_.conf().network()->peercast_server()),
  pcraw_proxy_server_(app_.conf().network()->pcraw_proxy_server()),
  disable_ipv6_      (_("Disable IPv6")),
  use_cache_         (_("Use cache")),
  yplist_            (app, parent)
{
  peercast_server_id_.set_width_chars(8);
  peercast_server_pw_.set_width_chars(8);
  peercast_server_pw_.set_visibility(false);

  SETUP_SPINBUTTON(timeout_,             1, 120);
  SETUP_SPINBUTTON(autoretry_limit_,     0,  10);
  SETUP_SPINBUTTON(autoretry_interval_, 10, 120);
  SETUP_SPINBUTTON(time_keep_ended_,     0, 100);

  Gtk::Table *t1 = Gtk::manage(new Gtk::Table());
  TABLE_LABEL(*t1, 0, _("PeerCast server"));
  TABLE_LABEL_F(*t1, 2, 0, _("ID"));
  TABLE_LABEL_F(*t1, 4, 0, _("PW"));
  TABLE_LABEL(*t1, 1, _("pcraw_proxy server"));
  TABLE_LABEL(*t1, 2, _("User-Agent"));
  TABLE_LABEL(*t1, 3, _("Timeout"));
  TABLE_LABEL(*t1, 4, _("Auto retry limit"));
  TABLE_LABEL(*t1, 5, _("Auto retry interval"));
  t1->attach(peercast_server_,    1, 2, 0, 1);
  t1->attach(peercast_server_id_, 3, 4, 0, 1);
  t1->attach(peercast_server_pw_, 5, 6, 0, 1);
  t1->attach(pcraw_proxy_server_, 1, 6, 1, 2);
  t1->attach(useragent_,          1, 6, 2, 3);
  t1->attach(timeout_,            1, 6, 3, 4);
  t1->attach(autoretry_limit_,    1, 6, 4, 5);
  t1->attach(autoretry_interval_, 1, 6, 5, 6);
  t1->attach(disable_ipv6_,       0, 6, 6, 7);
  TABLE_SPACING(*t1, 2, 2);
  pack_start(*t1, false, false);

  Gtk::Table *t2 = Gtk::manage(new Gtk::Table());
  TABLE_LABEL(*t2, 0, _("Time to keep ended channels(hour)"));
  t2->attach(time_keep_ended_, 1, 2, 0, 1);
  t2->attach(use_cache_,       0, 2, 1, 2);
  TABLE_SPACING(*t2, 2, 2);
  Gtk::ScrolledWindow *sw1 = Gtk::manage(new Gtk::ScrolledWindow());
  sw1->add(yplist_);
  sw1->set_shadow_type(Gtk::SHADOW_IN);
  sw1->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  Gtk::Button *b_u = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_UP));
  Gtk::Button *b_d = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_DOWN));
  Gtk::Button *b_a = Gtk::manage(new Gtk::Button(Gtk::Stock::ADD));
  Gtk::Button *b_r = Gtk::manage(new Gtk::Button(Gtk::Stock::REMOVE));
  Gtk::Button *b_f = Gtk::manage(new Gtk::Button(_("Add to favorite")));
  b_u->signal_clicked().connect(sigc::mem_fun(yplist_, &YPList::up));
  b_d->signal_clicked().connect(sigc::mem_fun(yplist_, &YPList::down));
  b_a->signal_clicked().connect(sigc::mem_fun(yplist_, &YPList::add));
  b_r->signal_clicked().connect(sigc::mem_fun(yplist_, &YPList::remove));
  b_f->signal_clicked().connect(sigc::mem_fun(yplist_, &YPList::add_favorite));
  Gtk::VBox *v1 = Gtk::manage(new Gtk::VBox(false, 2));
  v1->pack_start(*b_u, false, false);
  v1->pack_start(*b_d, false, false);
  v1->pack_start(*b_a, false, false);
  v1->pack_start(*b_r, false, false);
  v1->pack_end  (*b_f, false, false);
  Gtk::HBox *h1 = Gtk::manage(new Gtk::HBox(false, 2));
  h1->pack_start(*sw1);
  h1->pack_end(*v1, false, false);
  Gtk::VBox *v2 = Gtk::manage(new Gtk::VBox(false, 2));
  v2->pack_start(*t2, false, false);
  v2->pack_start(*h1);
  v2->set_border_width(2);
  Gtk::Frame *f1 = Gtk::manage(new Gtk::Frame(_("YellowPage")));
  f1->add(*v2);
  pack_start(*f1);

  ConfMain::RefNetwork net = app_.conf().network();
  net->peercast_server_id()->attach(peercast_server_id_.property_text());
  net->peercast_server_pw()->attach(peercast_server_pw_.property_text());
  net->useragent()         ->attach(useragent_         .property_text());
  net->timeout()           ->attach(timeout_           .property_value());
  net->autoretry_limit()   ->attach(autoretry_limit_   .property_value());
  net->autoretry_interval()->attach(autoretry_interval_.property_value());
  net->disable_ipv6()      ->attach(disable_ipv6_      .property_active());

  RefYPCollection ypc = app_.ypcollection();
  ypc->time_keep_ended()->attach(time_keep_ended_.property_value());
  ypc->use_cache()      ->attach(use_cache_      .property_active());

  ua_on_changed();
  conn_ua_changed_ = net->useragent()->signal_changed()
    .connect(sigc::mem_fun(*this, &Network::ua_on_changed));
}

}/*pref*/
}/*gpyp*/
